using System;
using System.Web;
using System.Text.RegularExpressions;
using System.Configuration;

namespace Impact.Web.Foundation.Handlers
{

    /// <summary>
    /// ExternalAccessModule prevents external access to resources
    /// courtesy of Mads Kristensen: http://feeds.feedburner.com/~r/netSlave/~3/90768165/PermaLink,guid,c557cdff-1aad-4d89-9562-3f92091a4aa5.aspx
    /// IIS must map any file extensions listed in the Web.config for this
    /// module to check them.
    /// </summary>
    public class ExternalAccessModule : IHttpModule
    {

        #region IHttpModule Members

        /// <summary>
        /// dispose
        /// </summary>
        public void Dispose()
        {
            // Nothing to dispose
        }

        /// <summary>
        /// hook up event handlers to the system events
        /// </summary>
        public void Init(HttpApplication context)
        {
            context.BeginRequest += new EventHandler(BeginRequest);
        }

        #endregion

        private void BeginRequest(object sender, EventArgs e)
        {
            HttpContext context = HttpContext.Current;

            // Do nothing if the request is legal
            if (ReguestIsLegal(context))
                return;

            // Accessed directly
            if (context.Request.UrlReferrer == null)
            {
                context.Response.StatusCode = 401;
                context.Response.Write("Access denied");
                context.Response.End();
            }

            // Linked to or embedded into another domain
            if (context.Request.UrlReferrer.Host != context.Request.Url.Host)
            {
                context.Response.StatusCode = 401;
                context.Response.Write("Access denied");
                context.Response.End();
            }
        }

        /// <summary>
        /// Checks the incomming request and checks if it 
        /// match the mappings in the web.config.
        /// </summary>
        /// <returns>True if the request didn't match the blocked list.</returns>
        private bool ReguestIsLegal(HttpContext context)
        {
            string mappings = ConfigurationManager.AppSettings["ExternalAccessModule:BlockMapping"];
            string fileName = context.Request.PhysicalPath;

            foreach (string map in mappings.Split('|'))
            {
                string cleaned = map.Replace("*", ".*").Replace(".", "\\.");
                if (Regex.IsMatch(fileName, cleaned, RegexOptions.IgnoreCase))
                    return false;
            }

            return true;
        }
    }

}